package com.example.identifyvisio.utis;

import com.example.identifyvisio.enumeration.NodeType;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.example.identifyvisio.utis.NodeValueUtil.getCellValue;
import static com.example.identifyvisio.utis.ProcessFileUtil.getText;

/**
 * 节点逻辑处理
 */

public class VisioFileUtil {
    /**
     * 解析masters文件获取各中类型的Master值
     *
     * @param masterFilePath
     * @return
     * @throws Exception
     */
    public static HashMap<String, String> getTypeMap(String masterFilePath) throws Exception {
        HashMap<String, String> typeMap = new HashMap<>(6);

        File xmlFile = new File(masterFilePath);
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.parse(xmlFile);
        doc.getDocumentElement().normalize();
        NodeList masterNodes = doc.getElementsByTagName("Master");
        for (int i = 0; i < masterNodes.getLength(); i++) {
            Element shapeElement = (Element) masterNodes.item(i);

            String shapeMaster = shapeElement.getAttribute("ID");
            String nameU = shapeElement.getAttribute("NameU");
            if (nameU.contains("rocess")){
                typeMap.put(shapeMaster, NodeType.PROCESS_TYPE.getMessage());
            }
            //获取节点的类型
            switch (nameU) {
                case "Start/End":
                    typeMap.put(shapeMaster, NodeType.START_TYPE.getMessage());
                    break;
                case "Decision":
                    typeMap.put(shapeMaster, NodeType.DECISION_TYPE.getMessage());
                    break;
                case "Swimlane":
                    typeMap.put(shapeMaster, NodeType.SWIMLANE_TYPE.getMessage());
                    break;
                case "Swimlane (vertical)":
                    typeMap.put(shapeMaster, NodeType.SWIMLANE_VERTICAL_TYPE.getMessage());
                    break;
                case "Dynamic connector":
                    typeMap.put(shapeMaster, NodeType.CONNECTOR_TYPE.getMessage());
                    break;
                default:
                    break;
            }
        }
        return typeMap;
}

    /**
     * 获取page1文件中的整体数据
     * 1.解析masters文件获取所需的各种类型的Master值
     * 2.遍历page1文件，根据Master值获取各节点所需的数据
     * 3.将每个节点的数据存储到一个HashMap中
     *
     * @param pageFilePath
     * @return
     */
    public static ArrayList<HashMap<Integer, Map<String, String>>> getDataMap(String pageFilePath, HashMap<String, String> typeMap) throws Exception {

        // 存储整体的数据
        HashMap<Integer, Map<String, String>> nodeDataMap = new HashMap<>();
        HashMap<Integer, Map<String, String>> laneDataMap = new HashMap<>();

        File xmlFile = new File(pageFilePath);
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc = dBuilder.parse(xmlFile);
        doc.getDocumentElement().normalize();
        NodeList shapeNodes = doc.getElementsByTagName("Shape");

        AtomicInteger laneCounter = new AtomicInteger(-1);
        AtomicInteger startCounter = new AtomicInteger(-1);
        AtomicInteger serviceTaskCounter = new AtomicInteger(-1);
        AtomicInteger choiceCounter = new AtomicInteger(-1);
        AtomicInteger succeedCounter = new AtomicInteger(-1);
        AtomicInteger failCounter = new AtomicInteger(-1);

        IntStream.range(0, shapeNodes.getLength())
                .mapToObj(i -> (Element) shapeNodes.item(i))
                .filter(shapeElement -> typeMap.containsKey(shapeElement.getAttribute("Master")))
                .forEach(shapeElement -> {
                    String shapeMaster = shapeElement.getAttribute("Master");
                    String text = getText(shapeElement.getElementsByTagName("Text"));
                    HashMap<String, String> hashMap = new HashMap<>();
                    String shapeID = getCommonData(shapeElement, shapeMaster, text, hashMap);

                    switch (typeMap.get(shapeMaster)) {
                        case "水平泳道":
                            hashMap.put("stateId", "lanePro0");
                            hashMap.put("type", "水平泳道");
                            laneDataMap.put(Integer.valueOf(shapeID), hashMap);
                            break;
                        case "动态连接线":
                            int choice = choiceCounter.incrementAndGet();
                            extractConnectionLines(choice, shapeElement, hashMap);
                            break;
                        case "垂直泳道":
                            int lane = laneCounter.incrementAndGet();
                            hashMap.put("stateId", "lane" + lane);
                            hashMap.put("type", "垂直泳道");
                            laneDataMap.put(Integer.valueOf(shapeID), hashMap);
                            break;
                        case "流程":
                            int serviceTask = serviceTaskCounter.incrementAndGet();
                            hashMap.put("stateId", "ServiceTask" + serviceTask);
                            hashMap.put("type", "流程");
                            break;
                        case "开始/结束":
                            if (NodeType.SUCCESS.getMessage().equals(text)) {
                                int succeed = succeedCounter.incrementAndGet();
                                hashMap.put("stateId", "Succeed" + succeed);
                                hashMap.put("type", "成功");
                            } else if (NodeType.FAIL.getMessage().equals(text)) {
                                int fail = failCounter.incrementAndGet();
                                hashMap.put("stateId", "Fail" + fail);
                                hashMap.put("type", "失败");
                            } else {
                                int start = startCounter.incrementAndGet();
                                hashMap.put("stateId", "Start" + start);
                                hashMap.put("type", "开始");
                            }
                            break;
                        case "判定":
                            hashMap.put("type", "判断");
                            break;
                        default:
                            // 忽略未知类型
                            break;
                    }
                    nodeDataMap.put(Integer.valueOf(shapeID), hashMap);
                });

        if (laneDataMap.size() == 0){
            setHorizontalLanes(nodeDataMap, laneDataMap);
        }

        //根据泳道的X坐标进行排序，防止最后在visio最左边新增泳道的情况
        LinkedHashMap<Integer, Map<String, String>> sortedNodeDataMap = getIntegerMapLinkedHashMap(laneDataMap);

        return new ArrayList<>(Arrays.asList(sortedNodeDataMap, nodeDataMap));
    }

    /**
     * 无泳道有节点时自定义水平泳道
     * @param nodeDataMap
     * @param laneDataMap
     */
    private static void setHorizontalLanes(HashMap<Integer, Map<String, String>> nodeDataMap, HashMap<Integer, Map<String, String>> laneDataMap) {
        Map<String, String> stringMap = nodeDataMap.get(nodeDataMap.keySet().iterator().next());
        HashMap<String, String> hashMap = new HashMap<>(9);
        // 生成随机的UUID
        UUID uuid = UUID.randomUUID();
        // 将UUID转换成字符串形式
        String uniqueID = uuid.toString();

        double PinX = Double.parseDouble(stringMap.get("PinX")) - 20 + (277 / 2);
        double PinY = Double.parseDouble(stringMap.get("PinY")) + 20 - (33/ 2);

        hashMap.put("UniqueID", uniqueID);
        hashMap.put("PinX", PinX + "");
        hashMap.put("PinY", PinY + "");
        hashMap.put("relationships", "");
        hashMap.put("sum", "0");
        hashMap.put("enterJudgment", "false");
        hashMap.put("stateId", "lanePro0");
        hashMap.put("type", "水平泳道");
        hashMap.put("text", "自定义水平泳道（0）");
        laneDataMap.put(0,hashMap);
        nodeDataMap.put(0, hashMap);
    }

    /**
     * 根据泳道的X坐标进行排序，防止最后在visio最左边新增泳道的情况
     * @param laneDataMap
     * @return
     */
    private static LinkedHashMap<Integer, Map<String, String>> getIntegerMapLinkedHashMap(HashMap<Integer, Map<String, String>> laneDataMap) {
        // 指定要排序的键
        String keyToSortBy = "PinX"; // 你可以根据需要更改这个键
        // 对第一层 Map 按照第二层 Map 中指定键的值排序
        LinkedHashMap<Integer, Map<String, String>> sortedNodeDataMap = laneDataMap.entrySet()
                .stream()
                .sorted(Comparator.comparing(entry ->
                        // 获取第二层 Map 中指定键的值，并转换为 Double 进行比较
                        Double.parseDouble(entry.getValue().getOrDefault(keyToSortBy, "0"))
                ))
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (e1, e2) -> e1, // 处理冲突的合并函数
                        LinkedHashMap::new // 保持插入顺序
                ));
        return sortedNodeDataMap;
    }


    /**
     * 获取节点的公共数据
     *
     * @param shapeElement
     * @param shapeMaster
     * @param text
     * @param hashMap
     * @return
     */
    public static String getCommonData(Element shapeElement, String shapeMaster, String text, HashMap<String, String> hashMap) {
        String relationships = getCellValue(shapeElement, "Relationships");
        hashMap.put("relationships", relationships);
        String shapeID = shapeElement.getAttribute("ID");
        String uniqueID = shapeElement.getAttribute("UniqueID");
        if (!"".equals(uniqueID)){
            String substring = uniqueID.substring(1, uniqueID.length() - 1);
            hashMap.put("UniqueID", substring);
        }else {
            // 生成随机的UUID
            UUID uuid = UUID.randomUUID();
            // 将UUID转换成字符串形式
            String unID = uuid.toString();
            hashMap.put("UniqueID", unID);
        }
        double PinX = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "PinX")) * 25.4);
        double PinY = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "PinY")) * 25.4);

        if (getCellValue(shapeElement, "Width") != null) {
            double width = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "Width")) * 25.4);
            hashMap.put("Width", String.valueOf(width));
        }
        if (getCellValue(shapeElement, "Height") != null) {
            double height = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "Height")) * 25.4);
            hashMap.put("Height", String.valueOf(height));
        }
        hashMap.put("text", text);
        hashMap.put("Master", shapeMaster);

        hashMap.put("PinX", PinX + "");
        hashMap.put("PinY", PinY + "");

        hashMap.put("sum", "0");
        hashMap.put("enterJudgment", "false");
        return shapeID;
    }


    /**
     * 提取连接线相关信息
     *
     * @param choice
     * @param shapeElement
     * @param hashMap
     */
    public static void extractConnectionLines(int choice, Element shapeElement, HashMap<String, String> hashMap) {
        double BeginX = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "BeginX")) * 25.4);
        double BeginY = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "BeginY")) * 25.4);
        double EndX = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "EndX")) * 25.4);
        double EndY = Math.ceil(Double.parseDouble(getCellValue(shapeElement, "EndY")) * 25.4);
        hashMap.put("stateId", "Choice" + choice);
        hashMap.put("type", "连接线");
        hashMap.put("BeginX", String.valueOf(BeginX));
        hashMap.put("BeginY", String.valueOf(BeginY));
        hashMap.put("EndX", String.valueOf(EndX));
        hashMap.put("EndY", String.valueOf(EndY));
    }
}
